using Abp.AspNetCore;
using Batman.Cms.Core;
using Batman.Cms.Core.Providers;
using Batman.Identity.Config;
using Batman.Identity.Data;
using Batman.IdentityServer.Extension.Core.Entities;
using IdentityServer4.EntityFramework.DbContexts;
using IdentityServer4.EntityFramework.Mappers;
using IdentityServer4.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
using System.Reflection;

namespace Batman.Identity.Startups
{
    public class Startup
    {
        private readonly IHostingEnvironment _hostingEnvironment;

        public Startup(IConfiguration configuration, IHostingEnvironment hostingEnvironment)
        {
            Configuration = configuration;
            _hostingEnvironment = hostingEnvironment;
        }

        public IConfiguration Configuration { get; }

        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            var connectionString = Configuration.GetConnectionString("DefaultConnection");
            services.AddDbContext<BatmanIdentityDbContext>(options => options.UseMySql(connectionString));

            services.AddDefaultIdentity<User>()
                    .AddEntityFrameworkStores<BatmanIdentityDbContext>()
                    .AddDefaultTokenProviders();

            var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
            // 后面的Migration必须写，不然会无法使用ef迁移
            services.AddDbContext<ConfigurationDbContext>(options => options.UseMySql(connectionString, b => b.MigrationsAssembly(migrationsAssembly)));


            //services.AddAuthentication("Bearer").

            services.AddIdentityServer()
                    .AddDeveloperSigningCredential()
                    .AddConfigurationStore(options =>
                    {
                        options.ConfigureDbContext = builder => builder.UseMySql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
                    })
                    .AddOperationalStore(options =>
                    {
                        options.ConfigureDbContext = builder => builder.UseMySql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
                        options.EnableTokenCleanup = true;
                        options.TokenCleanupInterval = 3600;
                    })
                    .AddAspNetIdentity<User>();

            services.AddBatmanCore(true);
            services.AddRbacPolicy(); // 添加RBAC策略

            return services.AddAbp<BatmanIdentityModule>();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            InitializeDatabase(app);
            //InitUserDatabase(app);

            app.UseAbp();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseDatabaseErrorPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();

            // app.UseAuthentication(); 
            app.UseIdentityServer();

            app.UseBatmanCore(env, false);

            //app.UseSwagger();
        }

        private void InitializeDatabase(IApplicationBuilder app)
        {
            using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
            {
                serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();

                var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
                context.Database.Migrate();
                if (!context.Clients.Any())
                {
                    foreach (var client in IdentityConfig.GetClients())
                    {
                        context.Clients.Add(client.ToEntity());
                    }
                    context.SaveChanges();
                }

                if (!context.IdentityResources.Any())
                {
                    foreach (var resource in IdentityConfig.GetIdentityResources())
                    {
                        context.IdentityResources.Add(resource.ToEntity());
                    }
                    context.SaveChanges();
                }

                if (!context.ApiResources.Any())
                {
                    foreach (var resource in IdentityConfig.GetApiResources())
                    {
                        context.ApiResources.Add(resource.ToEntity());
                    }
                    context.SaveChanges();
                }
            }
        }

        private async void InitUserDatabase(IApplicationBuilder app)
        {
            using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
            {
                var context = serviceScope.ServiceProvider.GetService<BatmanIdentityDbContext>();
                var userManager = serviceScope.ServiceProvider.GetService<UserManager<BatmanUser>>();

                if (!context.Users.Any())
                {
                    foreach (var user in IdentityConfig.GetUsers())
                    {
                        var entity = new BatmanUser
                        {
                            UserName = user.Username
                        };

                        entity.PasswordHash = userManager.PasswordHasher.HashPassword(entity, user.Password);

                        var createResult = await userManager.CreateAsync(entity);
                    }
                }
                //if (!context.Roles.Any())
                //{
                //    var roleManager = serviceScope.ServiceProvider.GetService<RoleManager<IdentityRole>>();

                //    foreach (var role in IdentityConfig.GetRoles())
                //    {
                //        var createResult = await roleManager.CreateAsync(role);
                //    }
                //}
            }
        }
    }

}
